#include "minet_socket.h"
#include <stdlib.h>
#include <ctype.h>
#include <iostream>
using namespace std;
#define BUFSIZE 1024

int main(int argc, char * argv[]) {

    char * server_name = NULL;
    int server_port    = -1;
    char * server_path = NULL;
    char * req         = NULL;
    bool ok            = false;

    int socket_id;
    struct hostent *he;
    struct sockaddr_in server_sa;
    int rcv;
    char buf[BUFSIZE];
    fd_set id_set;

    /*parse args */
    if (argc != 5) {
	fprintf(stderr, "usage: http_client k|u server port path\n");
	exit(-1);
    }

    server_name = argv[2];
    server_port = atoi(argv[3]);
    server_path = argv[4];

    req = (char *)malloc(strlen("GET  HTTP/1.0\r\n\r\n") + strlen(server_path) + 1);  

    /* initialize */
    if (toupper(*(argv[1])) == 'K') { 
	minet_init(MINET_KERNEL);
    } else if (toupper(*(argv[1])) == 'U') { 
	minet_init(MINET_USER);
    } else {
	fprintf(stderr, "First argument must be k or u\n");
	exit(-1);
    }

    /* make socket */
    socket_id = minet_socket(SOCK_STREAM);

    /* get host IP address  */
    /* Hint: use gethostbyname() */
    he = gethostbyname(server_name);

    if(he == 0) {
        fprintf (stderr, "Unknown host.\n");
        minet_close(socket_id);
        minet_deinit();
	free(req);
	return -1;
    }

    /* set address */
    bzero(&server_sa,sizeof(server_sa));
    server_sa.sin_family=AF_INET;
    memcpy((void*)(&(server_sa.sin_addr)),he->h_addr,he->h_length);
    server_sa.sin_port=htons(server_port);


    /* connect to the server socket */
    if(minet_connect(socket_id,&server_sa) < 0) 
    {
   	fprintf(stderr, "Can't connect to socket.\n");
	minet_perror("reason: ");
	minet_close(socket_id);
	minet_deinit();
	free(req);
	return -1;
    }

    /* send request message */
    sprintf(req, "GET %s HTTP/1.0\r\n\r\n", server_path);
    if(minet_write(socket_id, req, strlen(req)) < 0) 
    {
    	fprintf(stderr, "write failed.\n");
	minet_perror("reason: ");
	minet_close(socket_id);
	minet_deinit();
	free(req);
	return -1;
    }
    /* wait till socket can be read. */
    /* Hint: use select(), and ignore timeout for now. */
    FD_SET(socket_id, &id_set);
    if(minet_select(socket_id+1, &id_set, NULL, NULL, NULL) < 0) {
	fprintf(stderr, "Error using select socket.\n");
	minet_close(socket_id);
	minet_deinit();
    }
    /* first read loop -- read headers */
    string responsetext = "";
    string headertext = "";

    string::size_type pos;
    while( (rcv = minet_read(socket_id, buf, BUFSIZE-1)) > 0) 
    {
    	buf[rcv] = '\0';
	responsetext += string(buf);
	if(( pos = responsetext.find("\r\n\r\n",0)) != string::npos)
	{
	    headertext = responsetext.substr(0, pos);
	    responsetext = responsetext.substr(pos+4);
	    break;
	}
    }
    /* examine return code */   

    string statuscodestr = headertext.substr(headertext.find(" ")+1);
    statuscodestr = statuscodestr.substr(0, statuscodestr.find(" "));
    //Skip "HTTP/1.0"
    //remove the '\0'

    //cout << statuscodestr << endl;
    // Normal reply has return code 200
    if(statuscodestr == "200")
    {
	ok = true;
	cout << responsetext;
    }
    else
    {
    	/* print first part of response: header, error code, etc. */
    	ok = false;
	std::cerr << headertext + "\r\n\r\n" + responsetext;
    }
    /* second read loop -- print out the rest of the response: real web content */
    while(( rcv = minet_read(socket_id, buf, BUFSIZE-1)) > 0 )
    {
	buf[rcv] = '\0';
	if(ok)
	    printf("%s", buf);
	else
	    fprintf(stderr, buf);
    }
    /*close socket and deinitialize */
    minet_close(socket_id);
    minet_deinit();
    free(req);
    if (ok) {
	return 0;
    } else {
	return -1;
    }
}
